<!--
 * @author luguoxiang
 * @date 2022/9/17
 * 开源项目：https://gitee.com/lgx1992/lg-soar 求star！请给我star！请帮我点个star！
-->
<template>
  <slot :open="open" :show-info="showInfo">
    <t-tag-input
      v-if="input"
      ref="inputRef"
      :value="showInfo"
      v-bind="$attrs"
      readonly
      :disabled="disabled"
      @click="open"
    />
  </slot>
  <Teleport to="body">
    <t-dialog
      v-if="opened"
      v-model:visible="visible"
      header="选择人员"
      width="900px"
      mode="modeless"
      class="lg-modal user-picker-modal"
      draggable
      @confirm="ok"
      @closed="closed"
    >
      <div class="user-picker lg-grid" style="--grid: 2; --grid-space-v: 0px; height: 60vh">
        <div>
          <t-input
            placeholder="搜索用户"
            :value="keyword"
            style="margin-bottom: var(--app-space-vertical)"
            @change="search"
          />
          <div v-show="keyword" class="user-picker-user">
            <checkbox-list :list="userList" :value="ids" @change="change" />
          </div>
          <t-tabs v-show="!keyword" v-model:value="type" class="gl-tabs-auto-h">
            <t-tab-panel value="LAST" label="最近" :destroy-on-hide="false">
              <div style="margin-bottom: var(--app-space-vertical)"></div>
              <checkbox-list :list="lastList" :value="ids" @change="lastchange" />
            </t-tab-panel>
            <t-tab-panel value="TAG" label="标签" :destroy-on-hide="false">
              <t-tree :data="tagList" line :load="loadByTag" expand-on-click-node hover>
                <template #label="{ node: { data } }">
                  <t-checkbox
                    v-if="data.type === 'USER'"
                    :checked="ids.includes(data.id)"
                    @change="treechange($event, data)"
                  >
                    <t-avatar :image="getFileAccessAuthUrl(data.avatar)" :hide-on-load-failed="false">
                      {{ data.name.substring(data.name.length - 2) }}
                    </t-avatar>
                    {{ data.name }}
                    <span class="gl-color-placeholder">（{{ data.other }}）</span>
                  </t-checkbox>
                  <template v-else>
                    {{ data.name }}
                  </template>
                </template>
              </t-tree>
            </t-tab-panel>
            <t-tab-panel value="ORG" label="组织机构" :destroy-on-hide="false">
              <t-tree :data="orgList" line :load="loadByOrg" expand-on-click-node hover>
                <template #label="{ node: { data } }">
                  <t-checkbox
                    v-if="data.type === 'USER'"
                    :checked="ids.includes(data.id)"
                    @change="treechange($event, data)"
                  >
                    <t-avatar :image="getFileAccessAuthUrl(data.avatar)" :hide-on-load-failed="false">
                      {{ data.name.substring(data.name.length - 2) }}
                    </t-avatar>
                    {{ data.name }}
                    <span class="gl-color-placeholder">（{{ data.other }}）</span>
                  </t-checkbox>
                  <template v-else>
                    <span :class="'inner-tag-' + data.other">
                      <lg-text options="OrgTypeEnum" :model-value="data.other" />
                    </span>
                    {{ data.name }}
                  </template>
                </template>
              </t-tree>
            </t-tab-panel>
          </t-tabs>
        </div>
        <div>
          <t-card :title="`已选择（${selection.length}）`" header-bordered>
            <template #actions>
              <a href="javascript:void(0)" @click="removeAll">清空</a>
            </template>
            <div v-for="(x, i) in selection" :key="x.id" class="user-picker-item">
              <t-avatar :image="getFileAccessAuthUrl(x.avatar)" :hide-on-load-failed="false">
                {{ x.name.substring(x.name.length - 2) }}
              </t-avatar>
              {{ x.name }}
              <span class="gl-color-placeholder">（{{ x.other }}）</span>
              <lg-icon value="close" @click="remove(i)" />
            </div>
          </t-card>
        </div>
      </div>
    </t-dialog>
  </Teleport>
</template>
<script setup lang="ts">
import { computed, nextTick, ref, watch } from 'vue';
import { debounce, distinct, getFileAccessAuthUrl, LgText } from '@/soar';
import CheckboxList from './CheckboxList.vue';
import api from './api';

const props = defineProps({
  modelValue: {
    type: Array,
  },
  /**
   * 是否只读
   */
  readonly: {
    type: Boolean,
    default: false,
  },
  /**
   * 是否禁用
   */
  disabled: {
    type: Boolean,
    default: false,
  },
  /**
   * 是否输入框形式
   */
  input: {
    type: Boolean,
    default: false,
  },
});
const emits = defineEmits(['ok', 'change', 'update:modelValue', 'labelChange']);
const opened = ref(false);
const visible = ref(false);
const type = ref('LAST');
const keyword = ref();
const userList = ref([]);
const lastList = ref([]);
const tagList = ref([]);
const orgList = ref([]);
const selection = ref([]);
const showInfo = ref([]);
const inputRef = ref();

const ids = computed(() => selection.value.map((x) => x.id));

function closed() {
  opened.value = false;
  inputRef.value?.blur?.();
}

function change(e: any) {
  checked(e, userList.value);
}

function lastchange(e: any) {
  checked(e, lastList.value);
}

function treechange(c: any, d) {
  if (c) {
    selection.value.push(d);
  } else {
    const index = selection.value.findIndex((x) => x.id === d.id);
    selection.value.splice(index, 1);
  }
}

function remove(i) {
  selection.value.splice(i, 1);
}

function removeAll() {
  selection.value = [];
}

function checked(e, list) {
  const removes = ids.value.filter((x) => !e.includes(x));
  const adds = e.filter((x) => !ids.value.includes(x));
  let ss = selection.value;
  ss = ss.filter((x) => !removes.includes(x.id));
  for (const a of adds) {
    const index = list.findIndex((x) => x.id === a);
    if (index !== -1) {
      ss.push(list[index]);
    }
  }
  selection.value = ss;
}

const queryUser = debounce(() => {
  api.query(keyword.value).then((res) => {
    userList.value = res;
  });
}, 250);

function search(e) {
  keyword.value = e;
  if (!keyword.value) {
    userList.value = [];
    return;
  }
  queryUser();
}

function loadByOrg({ data: { id } }) {
  return api.org(id).then((res) => {
    for (const x of res) {
      if (x.type === 'USER') {
        x.value = x.id;
      } else {
        x.value = `o:${x.id}`;
        x.children = x.descendantQuantity > 0;
      }
      delete x.descendantQuantity;
    }
    return res;
  });
}

function loadByTag({ data: { id } }) {
  return api.tag(id).then((res) => {
    for (const x of res) {
      if (x.type === 'USER') {
        x.value = x.id;
      } else {
        x.value = `t:${x.id}`;
        x.children = x.descendantQuantity > 0;
      }
      delete x.descendantQuantity;
    }
    return res;
  });
}

/**
 * 点击确定时
 */
function ok() {
  putLast();
  emits('ok', selection.value);
  if (props.input) {
    emits('change', ids.value);
    emits('update:modelValue', ids.value);
  }
  nextTick(() => {
    showInfo.value = selection.value.map((x) => x.name);
    emits('labelChange', showInfo.value);
    visible.value = false;
  });
}

function putLast() {
  let res = distinct(ids.value.concat(lastList.value.map((x) => x.id)), (x) => x);
  if (res.length > 50) {
    res = res.slice(0, 50);
  }
  localStorage.setItem('user-picker', res.join(','));
}

watch(
  () => props.modelValue,
  (v) => {
    if (!opened.value) {
      if (!v?.length) {
        showInfo.value = [];
        emits('labelChange', showInfo.value);
        return;
      }
      api.ids(v).then((res) => {
        showInfo.value = res.map((x) => x.name);
        emits('labelChange', showInfo.value);
      });
    }
  },
  { immediate: props.input },
);

function open(params: any) {
  if (props.disabled || props.readonly) {
    return;
  }
  opened.value = true;
  keyword.value = null;
  loadByTag({ data: { id: 0 } }).then((res) => {
    tagList.value = res;
  });
  loadByOrg({ data: { id: 0 } }).then((res) => {
    orgList.value = res;
  });
  let ls: string[];
  try {
    ls = localStorage.getItem('user-picker')?.split(',');
    if (!Array.isArray(ls)) {
      ls = [];
    }
  } catch (e) {
    localStorage.removeItem('user-picker');
    ls = [];
  }
  const vs = props.modelValue || [];
  const ids = vs.concat(ls);
  if (ids.length) {
    api
      .ids(distinct(ids, (x) => x))
      .then((res) => {
        selection.value = res.filter((x) => vs.includes(x.id));
        lastList.value = res.filter((x) => ls.includes(x.id));
        if (!lastList.value?.length) {
          type.value = 'ORG';
        }
      })
      .catch((err) => {
        if (err.response.status === 400) {
          localStorage.removeItem('user-picker');
        }
      });
  }
  nextTick(() => {
    visible.value = true;
  });
}

defineExpose({
  open,
});
</script>
<script lang="ts">
export default {
  name: 'UserMultiplePicker',
};
</script>
<style lang="less" scoped>
.user-picker {
  > div {
    height: 60vh;
  }
  .t-tabs,
  .user-picker-user {
    height: calc(100% - 42px);
  }
  .user-picker-user {
    overflow-y: auto;
  }

  .t-card {
    height: 100%;
  }

  :deep(.t-card__body) {
    height: calc(100% - 45.25px);
    overflow: auto;
    display: flex;
    flex-direction: column;
    gap: var(--app-space-vertical) 0;
  }
  .user-picker-item {
    width: 100%;
    position: relative;
    &:hover {
      background: var(--td-bg-color-container-hover);
      border-radius: 16px 3px 3px 16px;
      .t-icon-close {
        font-size: 22px;
      }
    }
  }
  .t-icon-close {
    position: absolute;
    right: 0;
    top: 50%;
    transform: translateY(-50%);
    color: red;
    font-size: 20px;
    transition: font-size;
  }
  .inner-tag-0 {
    color: var(--app-color-primary-5);
  }
  .inner-tag-1 {
    color: var(--app-color-primary);
  }
  .inner-tag-2 {
    color: var(--td-warning-color);
  }
  .inner-tag-3 {
    color: var(--td-success-color);
  }
}
</style>
